package org.feng.navigation.adapter.handler;

import lombok.extern.slf4j.Slf4j;
import org.feng.navigation.client.dto.*;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.Iterator;
import java.util.Set;

/**
 * 通用异常处理器
 *
 * <br> 参考：<a href="https://blog.csdn.net/qq_43409401/article/details/116017177">BindException、ConstraintViolationException、MethodArgumentNotValidException入参验证异常分析和全局异常处理解决方法</a>
 *
 * @version v1.0
 * @author: junzi
 * @date: 2023年01月11日 21时10分
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(Exception.class)
    public Response otherException(Exception exception) {
        log.error("全局处理异常，未知错误", exception);
        ErrorEnum error = ErrorEnum.APPLICATION_ERROR;
        return SingleResponse.buildFailure(error, "发生错误：" + exception.getMessage());
    }

    @ExceptionHandler({ConstraintViolationException.class})
    public Response handleConstraintViolationException(ConstraintViolationException ex) {
        Set<ConstraintViolation<?>> violations = ex.getConstraintViolations();
        Iterator<ConstraintViolation<?>> iterator = violations.iterator();
        IError error = ErrorEnum.METHOD_ARGUMENTS_VALID_ERROR;
        StringBuilder sb = new StringBuilder(error.getErrorMessage()).append("：");

        while (iterator.hasNext()) {
            ConstraintViolation<?> next = iterator.next();
            sb.append(next.getPropertyPath().toString().split("\\.")[1]).append("：").append(next.getMessage()).append(", ");
        }
        return SingleResponse.buildFailure(error, sb.toString());
    }

    /**
     * 拦截api方法参数校验异常
     *
     * @param exception api方法参数校验异常
     * @return 拦截到异常后，处理获取异常码、异常描述，封装为响应体返回
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public Response handleMethodArgumentNotValid(MethodArgumentNotValidException exception) {
        BindingResult bindingResult = exception.getBindingResult();
        IError error = ErrorEnum.METHOD_ARGUMENTS_VALID_ERROR;
        StringBuilder sb = new StringBuilder(error.getErrorMessage()).append("：");
        for (FieldError fieldError : bindingResult.getFieldErrors()) {
            sb.append("[").append(fieldError.getField()).append("]：").append(fieldError.getDefaultMessage()).append(Constant.ENGLISH_COMMA);
        }
        if (sb.toString().endsWith(Constant.ENGLISH_COMMA)) {
            sb.deleteCharAt(sb.length() - 1);
        }

        String errorMessage = sb.toString();
        log.info("参数校验错误：{}", errorMessage);
        return SingleResponse.buildFailure(error, errorMessage);
    }
}
